export class LocaleDB {
    db;

    projectName;

    objectStoreName;

    storeList = [];

    eventList = [];

    version = 1;

    constructor(projectName = 'default-project', storeName = 'default-store') {
        this.projectName = projectName;
        this.objectStoreName = storeName;
        this.ready(projectName, storeName);
    }

    ready(projectName = this.projectName, storeName = this.objectStoreName) {
        return new Promise((resolve, reject) => {
            if (this.db) {
                resolve(this);
            } else {
                const request = window.indexedDB.open(projectName, this.version);
                request.onsuccess = (event) => {
                    this.db = event.target.result;
                    resolve(this);
                };
                request.onupgradeneeded = (event) => {
                    const db = event.target.result;
                    if (!db.objectStoreNames.contains(storeName)) {
                        db.createObjectStore(storeName);
                        this.storeList.push(storeName);
                    }
                };
                request.onerror = (event) => {
                    reject(event);
                };
            }
        });
    }

    init(request, callback) {
        return new Promise((resolve, reject) => {
            const success = (value) => {
                if (callback && typeof callback === 'function') {
                    callback(false, value);
                }
                resolve(value);
            };
            const error = (event) => {
                if (callback && typeof callback === 'function') {
                    callback(event);
                }
                reject(event);
            };
            return this.ready()
                .then(() => {
                    request(success, error);
                })
                .catch(error);
        });
    }

    // 触发事件
    triggerEvent() {
        document.dispatchEvent(
            new CustomEvent('LocaleDB', {
                detail: [...arguments],
            })
        );
        this.eventList.forEach((fn) => {
            fn(...arguments);
        });
    }

    // 自定义事件
    addEventListener(callback) {
        this.eventList.push(callback);
    }

    addStore(storeName) {
        const v = this.version + 1;
        console.log(this.projectName, v);
        console.log(this.db);
        // const request = window.indexedDB.open(this.projectName, v);
        // console.log(request);
        // request.onupgradeneeded = (event) => {
        //     const db = event.target.result;
        //     console.log(this, db, '++++++++');
        // if (!db.objectStoreNames.contains(storeName)) {
        //     db.createObjectStore(storeName);
        //     this.storeList.push(storeName);
        // }
        // };
    }

    setItem(key, value, callback) {
        return this.init((success, error) => {
            const request = this.db
                .transaction(this.objectStoreName, 'readwrite')
                .objectStore(this.objectStoreName)
                .put(value, key);
            request.onsuccess = () => {
                success(value);
                this.triggerEvent('setItem', { key, value }, this.projectName);
            };
            request.onerror = error;
            // this.dispatchEvent(new CustomEvent('update'))
        }, callback);
    }

    getItem(key, callback) {
        return this.init((success, error) => {
            const request = this.db
                .transaction(this.objectStoreName)
                .objectStore(this.objectStoreName)
                .get(key);
            request.onsuccess = () => success(request.result);
            request.onerror = error;
        }, callback);
    }

    setItemPeriod(key, value, expired = 0, callback) {
        const saveData = {
            value,
            expired: new Date().getTime() + expired,
        };
        return this.init((success, error) => {
            const request = this.db
                .transaction(this.objectStoreName, 'readwrite')
                .objectStore(this.objectStoreName)
                .put(saveData, key);
            request.onsuccess = () => {
                success(saveData);
                this.triggerEvent('setItem', { key, saveData }, this.projectName);
            };
            request.onerror = error;
        }, callback);
    }

    getItemPeriod(key, callback) {
        return this.init((success, error) => {
            const request = this.db
                .transaction(this.objectStoreName)
                .objectStore(this.objectStoreName)
                .get(key);
            let gotData = null;
            if (request.result.expired > new Date().getTime()) {
                gotData = request.result;
            }
            request.onsuccess = () => success(gotData);
            request.onerror = error;
        }, callback);
    }

    removeItem(key, callback) {
        return this.init((success, error) => {
            const request = this.db
                .transaction(this.objectStoreName, 'readwrite')
                .objectStore(this.objectStoreName)
                .delete(key);
            request.onsuccess = () => {
                success(key);
                this.triggerEvent('removeItem', { key }, this.projectName);
            };
            request.onerror = error;
        }, callback);
    }

    key(index, callback) {
        return this.init((success, error) => {
            const request = this.db
                .transaction(this.objectStoreName)
                .objectStore(this.objectStoreName)
                .getAllKeys();
            request.onsuccess = () => success(request.result[index]);
            request.onerror = error;
        }, callback);
    }

    keys(callback) {
        return this.init((success, error) => {
            const request = this.db
                .transaction(this.objectStoreName)
                .objectStore(this.objectStoreName)
                .getAllKeys();
            request.onsuccess = () => success(request.result);
            request.onerror = error;
        }, callback);
    }

    clear(callback) {
        return this.init((success, error) => {
            const request = this.db
                .transaction(this.objectStoreName, 'readwrite')
                .objectStore(this.objectStoreName)
                .clear();
            request.onsuccess = () => {
                success(null);
                this.triggerEvent('clear', {}, this.projectName);
            };
            request.onerror = error;
        }, callback);
    }
}

window.globalDB = new LocaleDB();
export default window.globalDB;
